import 'dart:convert';

import 'package:dio/dio.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter_snail/network/request/base_entiry.dart';
import 'package:flutter_snail/network/snail_api.dart';

typedef NetSuccess = Function(BaseEntity baseEntity);
typedef NetError = Function(int? code, String msg);

class SnailRequest {
  late Dio _dio;
  Dio get dio => _dio;

  static SnailRequest? _instance;
  static SnailRequest get instance => _getInstance();

  SnailRequest._() {
    _dio = Dio();
    setBaseOptions();
  }

  static _getInstance() {
    _instance ??= SnailRequest._();
    return _instance;
  }

  setBaseOptions() {
    BaseOptions options = BaseOptions();
    options.connectTimeout = connectTimeOut;
    options.receiveTimeout = receiveTimeOut;
    options.baseUrl = SnailApi.baseUrl;
    _dio.options = options;
  }

  ///连接超时时间为5秒
  static const int connectTimeOut = 5 * 1000;

  ///响应超时时间为7秒
  static const int receiveTimeOut = 7 * 1000;

  // 数据返回格式统一，统一处理异常
  void _request(
    String method,
    String url, {
    Object? data,
    Map<String, dynamic>? queryParameters,
    CancelToken? cancelToken,
    Options? options,
    NetSuccess? onSuccess,
    NetError? onError,
  }) async {
    final Response<String> response = await _dio.request<String>(
      url,
      data: data,
      queryParameters: queryParameters,
      options: _checkOptions(method, options),
      cancelToken: cancelToken,
    );
    try {
      final String result = response.data.toString();

      /// 集成测试无法使用 isolate https://github.com/flutter/flutter/issues/24703
      /// 使用compute条件：数据大于10KB（粗略使用10 * 1024）且当前不是集成测试（后面可能会根据Web环境进行调整）
      /// 主要目的减少不必要的性能开销
      final bool isCompute = !kDebugMode && result.length > 10 * 1024;
      final Map<String, dynamic> map =
          isCompute ? await compute(parseData, result) : parseData(result);

      /// 请求成功
      onSuccess?.call(BaseEntity.fromJson(map));
    } catch (e) {
      debugPrint(e.toString());
      _handError(onError, response.statusCode);
      rethrow;
    }
  }

  Options _checkOptions(String method, Options? options) {
    options ??= Options();
    options.method = method;
    return options;
  }

  request(
    Method method,
    String url, {
    NetSuccess? onSuccess,
    NetError? onError,
    Object? params,
    Map<String, dynamic>? queryParameters,
    CancelToken? cancelToken,
    Options? options,
  }) {
    _request(
      method.value,
      url,
      data: params,
      queryParameters: queryParameters,
      options: options,
      cancelToken: cancelToken,
      onSuccess: onSuccess,
      onError: onError,
    );
  }

  ///处理异常
  static void _handError(NetError? errorCallback, int? statusCode) {
    String errorMsg = 'Network request error';
    errorCallback?.call(statusCode, errorMsg);
    debugPrint("HTTP_RESPONSE_ERROR::$errorMsg code:$statusCode");
  }
}

Map<String, dynamic> parseData(String data) {
  return json.decode(data) as Map<String, dynamic>;
}

enum Method { get, post, put, patch, delete, head }

/// 使用拓展枚举替代 switch判断取值
/// https://zhuanlan.zhihu.com/p/98545689
extension MethodExtension on Method {
  String get value => ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'HEAD'][index];
}
